#!/bin/sh

e2e_test_install() {
  create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 2

  deploy_curl_pod "$CLUSTER_NAMESPACE"

  wait_pods_running "$CLUSTER_NAMESPACE" 3
  wait_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE"
  switch_cluster_to_first "$CLUSTER_NAME" "$CLUSTER_NAMESPACE"
}

e2e_test() {
  run_test "Checking scaledown is working" check_scaledown

  run_test "Checking scaledown to zero is working" check_scalezero

  run_test "Checking that scaleup is working" check_scaleup

  run_test "Checking that switchover is working" check_switchover

  run_test "Checking scaledown is working when primary is the last pod" check_scaledown_when_primary_last_pod

  run_test "Checking delete primary when is beyond last pod" check_delete_primary_when_beyond_last_pod

  run_test "Checking that scaleup is working when primary is beyond last pod" check_scaleup_when_primary_beyond_last_pod
}

check_scaledown() {
  local PRIMARY_UID
  PRIMARY_UID="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 --template '{{ .metadata.uid }}')"

  check_cluster_pod_count 2

  local RESULT
  local EXIT_CODE
  try_function create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 1
  if "$RESULT"
  then
    success "The number of instances has been changed"
  else
    fail "Can not change the number of instances"
  fi

  try_function wait_pods_terminated "$CLUSTER_NAMESPACE" 1 "$CLUSTER_NAME-[01]"
  if "$RESULT"
  then
    success "The number of pods has changed"
  else
    fail "The number of pods did not changed"
  fi

  if kubectl get pod -n "$CLUSTER_NAMESPACE" -o name | grep -q "^pod/${CLUSTER_NAME}-1"
  then
    fail "The secondary instance was not disposed :("
  else
    success "The secondary instance was disposed!"
  fi

  local AFTER_SCALEDOWN_PRIMARY_UID
  AFTER_SCALEDOWN_PRIMARY_UID="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 --template '{{ .metadata.uid }}')"
  if [ "$AFTER_SCALEDOWN_PRIMARY_UID" = "$PRIMARY_UID" ]
  then
    success "The primary instance was not disposed!"
  else
    fail "The primary instance was disposed :("
  fi

  check_cluster_pod_count 1
}

check_scalezero() {
  check_cluster_pod_count 1

  local RESULT
  local EXIT_CODE
  try_function create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 0
  if "$RESULT"
  then
    success "The number of instances has been changed"
  else
    fail "Can not change the number of instances"
  fi

  try_function wait_pods_terminated "$CLUSTER_NAMESPACE" 0 "$CLUSTER_NAME-[01]"
  if "$RESULT"
  then
    success "The number of pods has changed"
  else
    fail "The number of pods did not changed"
  fi

  if kubectl get pod -n "$CLUSTER_NAMESPACE" -o name | grep -q "^pod/${CLUSTER_NAME}-"
  then
    fail_no_return "Some instance was not disposed :("
    kubectl get pod -n "$CLUSTER_NAMESPACE" -o name || true
    return 1
  else
    success "All instances were disposed!"
  fi

  check_cluster_pod_count 0

  local RESULT
  local EXIT_CODE
  try_function create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 1
  if "$RESULT"
  then
    success "The number of instances has been changed"
  else
    fail "Can not change the number of instances"
  fi

  try_function wait_pods_running "$CLUSTER_NAMESPACE" 1 "$CLUSTER_NAME-[01]"
  if "$RESULT"
  then
    success "The number of pods has changed"
  else
    fail "The number of pods did not changed"
  fi

  local AFTER_SCALEDOWN_PRIMARY_NAME
  AFTER_SCALEDOWN_PRIMARY_NAME="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 --template '{{ .metadata.name }}')"
  if kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 --template '{{ .metadata.name }}' | grep -qxF "$CLUSTER_NAME"-0 
  then
    success "The primary instance $CLUSTER_NAME-0 has been restored!"
  else
    fail "The primary instance $CLUSTER_NAME-0 was not restored :("
  fi

  check_cluster_pod_count 1
}

check_scaleup() {
  local PRIMARY_UID
  PRIMARY_UID="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 --template '{{ .metadata.uid }}')"

  local RESULT
  local EXIT_CODE
  try_function create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 2
  if "$RESULT"
  then
    success "The number of instances has been changed"
  else
    fail "Can not change the number of instances"
  fi

  try_function wait_pods_running "$CLUSTER_NAMESPACE" 2 "$CLUSTER_NAME-[01]"
  if "$RESULT"
  then
    success "The number of pods has changed"
  else
    fail "The number of pods did not changed"
  fi

  if kubectl get pod -n "$CLUSTER_NAMESPACE" -o name | grep -q "^pod/${CLUSTER_NAME}-1"
  then
    success "The secondary instance was created!"
  else
    fail "The secondary instance was not created :("
  fi

  local AFTER_SCALEUP_PRIMARY_UID
  AFTER_SCALEUP_PRIMARY_UID="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 --template '{{ .metadata.uid }}')"
  if [ "$AFTER_SCALEUP_PRIMARY_UID" = "$PRIMARY_UID" ]
  then
    success "The primary instance was not disposed!"
  else
    fail "The primary instance was disposed :("
  fi

  check_cluster_pod_count 2
}

check_switchover() {
  PATRONI_MAJOR_VERSION="$(kubectl exec -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME-0" -c patroni -- \
    patronictl version 2>/dev/null | sed -n 's/^patronictl version \([0-9]\+\)\..*$/\1/p')"
  if kubectl exec -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 -c patroni -- \
    patronictl switchover \
    $([ "$PATRONI_MAJOR_VERSION" -lt 4 ] && printf %s --master || printf %s --primary) "$CLUSTER_NAME"-0 \
    --candidate "$CLUSTER_NAME"-1 --force
  then
    success "The switchover has been performed"
  else
    fail "The switchover operation failed"
  fi

  local RESULT=false
  local START="$(date +%s)"
  while [ "$((START + E2E_TIMEOUT))" -gt "$(date +%s)" ]
  do
    if run_query -i 0 -p 5432
    then
      success "The replica becomed available"
      RESULT=true
      break
    fi
    sleep 2
  done
  if ! "$RESULT"
  then
    fail "The replica is not available"
  fi

  local IS_IN_RECOVERY="$(run_query -i 1 -p 5432 -q "SELECT pg_is_in_recovery()")"
  if [ "$IS_IN_RECOVERY" = 'f' ]
  then
    success "The primary is now the pod at index 1"
  else
    fail "The pod at index 1 is not the primary"
  fi

  local IS_IN_RECOVERY="$(run_query -i 0 -p 5432 -q "SELECT pg_is_in_recovery()")"
  if [ "$IS_IN_RECOVERY" = 't' ]
  then
    success "The replica is now the pod at index 0"
  else
    fail "The pod at index 0 is not a replica"
  fi

  check_cluster_pod_count 2
}

check_scaledown_when_primary_last_pod() {
  local PRIMARY_UID
  PRIMARY_UID="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-1 --template '{{ .metadata.uid }}')"

  local RESULT
  local EXIT_CODE
  try_function create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 1
  if "$RESULT"
  then
    success "The number of instances has been changed"
  else
    fail "Can not change the number of instances"
  fi

  try_function wait_pods_terminated "$CLUSTER_NAMESPACE" 1 "$CLUSTER_NAME-[01]"
  if "$RESULT"
  then
    success "The number of pods has changed"
  else
    fail "The number of pods did not changed"
  fi

  if kubectl get pod -n "$CLUSTER_NAMESPACE" -o name | grep -q "^pod/${CLUSTER_NAME}-1"
  then
    success "The primary instance was not disposed!"
  else
    fail "The primary instance was disposed :("
  fi

  local AFTER_SCALEDOWN_PRIMARY_UID
  AFTER_SCALEDOWN_PRIMARY_UID="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-1 --template '{{ .metadata.uid }}')"
  if [ "$AFTER_SCALEDOWN_PRIMARY_UID" = "$PRIMARY_UID" ]
  then
    success "The primary instance was not disposed!"
  else
    fail "The primary instance was disposed :("
  fi

  check_cluster_pod_count 1
}

check_delete_primary_when_beyond_last_pod() {
  run_query -i 1 -p 5432 -q 'CREATE TABLE test AS SELECT generate_series(1, 1000000) i;'

  kubectl delete pod -n "$CLUSTER_NAMESPACE" "${CLUSTER_NAME}-1"

  try_function wait_pods_running "$CLUSTER_NAMESPACE" 1 "${CLUSTER_NAME}-1"
  if "$RESULT"
  then
    success "Primary pod started after deleting it"
  else
    fail "Primary pod didn't started after deleting it"
  fi

  local IS_IN_RECOVERY="$(run_query -i 1 -p 5432 -q "SELECT pg_is_in_recovery()")"
  if [ "$IS_IN_RECOVERY" = 'f' ]
  then
    success "The primary is still the pod at index 1"
  else
    fail "The pod at index 1 is not the primary"
  fi

  wait_until eval 'kubectl get pod -n "$CLUSTER_NAMESPACE" \
    -l "app=StackGresCluster,stackgres.io/cluster-name=$CLUSTER_NAME,stackgres.io/cluster=true" -o name \
    | wc -l | grep -q "^1$"'

  check_cluster_pod_count 1
}

check_scaleup_when_primary_beyond_last_pod() {
  local PRIMARY_UID
  PRIMARY_UID="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-1 --template '{{ .metadata.uid }}')"

  local RESULT
  local EXIT_CODE
  try_function create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 2
  if "$RESULT"
  then
    success "The number of instances has been changed"
  else
    fail "Can not change the number of instances"
  fi

  try_function wait_pods_running "$CLUSTER_NAMESPACE" 2 "$CLUSTER_NAME-[01]"
  if "$RESULT"
  then
    success "The number of pods has changed"
  else
    fail "The number of pods did not changed"
  fi

  if kubectl get pod -n "$CLUSTER_NAMESPACE" -o name | grep -q "^pod/${CLUSTER_NAME}-1"
  then
    success "The primary instance was not disposed!"
  else
    fail "The primary instance was disposed :("
  fi

  local AFTER_SCALEUP_PRIMARY_UID
  AFTER_SCALEUP_PRIMARY_UID="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-1 --template '{{ .metadata.uid }}')"
  if [ "$AFTER_SCALEUP_PRIMARY_UID" = "$PRIMARY_UID" ]
  then
    success "The primary instance was not disposed!"
  else
    fail "The primary instance was disposed :("
  fi

  check_cluster_pod_count 2
}

check_cluster_pod_count() {
  local EXPECTED_INSTANCES="$1"
  local ACTUAL_INSTANCES
  ACTUAL_INSTANCES="$(get_all_cluster_pod_count)"
  if [ "$ACTUAL_INSTANCES" = "$EXPECTED_INSTANCES" ]
  then
    success "The number of instances returned by stackgres/sgclusters is $EXPECTED_INSTANCES"
  else
    fail "The number of instances returned by stackgres/sgclusters is $ACTUAL_INSTANCES"
  fi

  ACTUAL_INSTANCES="$(get_cluster_pod_count)"
  if [ "$ACTUAL_INSTANCES" = "$EXPECTED_INSTANCES" ]
  then
    success "The number of instances returned by stackgres/<namespace>/sgcluster/<name> is $EXPECTED_INSTANCES"
  else
    fail "The number of instances returned by stackgres/<namespace>/sgcluster/<name> is $ACTUAL_INSTANCES"
  fi

  ACTUAL_INSTANCES="$(get_cluster_stats_pod_count)"
  if [ "$ACTUAL_INSTANCES" = "$EXPECTED_INSTANCES" ]
  then
    success "The number of instances returned by stackgres/<namespace>/sgcluster/<name>/stats is $EXPECTED_INSTANCES"
  else
    fail "The number of instances returned by stackgres/<namespace>/sgcluster/<name>/stats is $ACTUAL_INSTANCES"
  fi
}

get_all_cluster_pod_count() {
  run_curl -r "stackgres/sgclusters" \
    | jq ".[]|select(.metadata.namespace == \"$CLUSTER_NAMESPACE\" and .metadata.name == \"$CLUSTER_NAME\")|.pods | length"
}

get_cluster_pod_count() {
  run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgclusters/$CLUSTER_NAME" | jq '.pods | length'
}

get_cluster_stats_pod_count() {
  run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgclusters/$CLUSTER_NAME/stats" | jq '.pods | length'
}
